package com.demo.config;

import java.io.IOException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.demo.core.jdbc.datasource.DataSourceFactoryBean;
import com.thetransactioncompany.util.PropertyParseException;
import com.thetransactioncompany.util.PropertyRetriever;

@Configuration
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppDataSource {
	@Bean
	@Value("classpath:jdbc.properties")
	public PropertyRetriever jdbcPr(Resource r) throws IOException {
		return new PropertyRetriever(PropertiesLoaderUtils.loadProperties(r));
	}

	/**
	 * 配置主数据源
	 */
	@Bean
	@Autowired
	public DataSourceFactoryBean masterDataSource(@Qualifier("jdbcPr") PropertyRetriever pr) throws PropertyParseException {
		DruidDataSource ds = parentDataSource(pr);
		ds.setUrl(pr.getString("mysql.url"));
		ds.setUsername(pr.getString("mysql.username"));
		ds.setPassword(pr.getString("mysql.password"));

		return debugDataSource(ds, pr.getBoolean("debug"));
	}

	@Bean
	@Autowired
	public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource ds) {
		DataSourceTransactionManager txManager = new DataSourceTransactionManager();
		txManager.setDataSource(ds);
		return txManager;
	}

	/**
	 * debug DataSource
	 */
	public DataSourceFactoryBean debugDataSource(DataSource ds, boolean debug) {
		DataSourceFactoryBean factory = new DataSourceFactoryBean();
		factory.setDataSource(ds);
		factory.setDebug(debug);
		return factory;
	}

	/**
	 * 基本数据源配置
	 */
	public DruidDataSource parentDataSource(PropertyRetriever pr) throws PropertyParseException {
		DruidDataSource ds = new DruidDataSource();
		// 初始化连接数量
		ds.setInitialSize(pr.getInt("druid.initialSize"));
		// 最大并发连接数
		ds.setMaxActive(pr.getInt("druid.maxActive"));
		// 最小空闲连接数
		ds.setMinIdle(pr.getInt("druid.minIdle"));
		// 配置获取连接等待超时的时间 
		ds.setMaxWait(pr.getLong("druid.maxWait"));
		// 超过时间限制是否回收 
		ds.setRemoveAbandoned(pr.getBoolean("druid.removeAbandoned"));
		// 超过时间限制多长； 
		ds.setRemoveAbandonedTimeout(pr.getInt("druid.removeAbandonedTimeout"));
		// 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 
		ds.setTimeBetweenEvictionRunsMillis(pr.getLong("druid.timeBetweenEvictionRunsMillis"));
		// 配置一个连接在池中最小生存的时间，单位是毫秒 
		ds.setMinEvictableIdleTimeMillis(pr.getLong("druid.minEvictableIdleTimeMillis"));
		// 申请连接的时候检测 
		ds.setTestWhileIdle(pr.getBoolean("druid.testWhileIdle"));
		// 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能 
		ds.setTestOnBorrow(pr.getBoolean("druid.testOnBorrow"));
		// 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能 
		ds.setTestOnReturn(pr.getBoolean("druid.testOnReturn"));
		// 打开PSCache，并且指定每个连接上PSCache的大小 
		ds.setPoolPreparedStatements(pr.getBoolean("druid.poolPreparedStatements"));
		ds.setMaxPoolPreparedStatementPerConnectionSize(pr.getInt("druid.maxPoolPreparedStatementPerConnectionSize"));
		// 用来检测连接是否有效的sql，要求是一个查询语句 
		ds.setValidationQuery(pr.getString("druid.validationQuery"));
		return ds;
	}
}
